/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com

	The Chickadee is an experimental 4-bit VM. 


	Instruction width = 4 bit
	Stack width = 16 bit
	Stack height = 16 bit
	Maximum types = 16 (4 bits) 
	Addressable Heap = ?
	Int size = 12 bit

*/

#ifndef CHICKADEE_HPP
#define CHICKADEE_HPP

namespace chickadee
{
	int* heap;
	int* stk;
	int* aux;
	char* code;
	char* end;
	int top;
	int opcode;
	int* funcs;

	// TODO: load the data from the standard stream into memory? Or something.
	
	// code, aux, stk, heap

	int exec() {
		while (code != end) 
		{
			switch (*code++) {

				// B A add_int -> B + A
				case op_add_int: 
					top += *--stk; 
					break;
				
				// B A op_shift -> A <= 8 ? B << A : B >> A - 8
				case op_shift: 
					if (*top <= 8) 
						*(top - 1) <<= *top; else 
						*(top - 1) >>= *top - 8; else 
					--top;
					break;
				
				// B A op_nand -> (B nand A)
				case op_nand: 
					top &= *--stk; 
					break;
				
				// A op_not -> not(A)
				case op_not: 
					top = ~top; 
					break;
				
				// A 
				case op_storeN: 
					// 
					tmp = stk - top;
					while (tmp != stk) {
						*aux++ = *tmp++;
					}
					stk = stk - top;
					top = *--stk;
					break;
				
				// 5
				case op_loadN: 
					tmp = aux - top;
					while (tmp != aux) {
						*aux++ = *tmp++;
					}
					stk = stk - top;
					top = *--stk;
					break;

				// 6
				case op_getN: 
					*stk = top; 
					top = stk[-top]; 

					++stk; 
					break;

				// 7
				case op_setN: 
					// N setN
					stk[-top] = stk[0]; 
					top = *--stk;
					break;

				// 8
				case op_push: 
					// push(x : byte)
					*stk++ = top; 
					top = *ic++ << 4;
					top |= *ic++;
					break;
				
				// 9
				case op_jnz: 
					// [f] bool 
					--stk; 
					if (top) 
						code = funcs[*stk]; 
					top = *--stk; 
					break;
				
				// 10
				case op_set_mem: 
					reinterpret_cast<char*>(heap + *stk - 2)[*stk - 1] = top; 
					top = stk - 2; 
					break;
				
				// 11
				case op_get_mem: 
					top = reinterpret_cast<char*>(heap + *--stk)[top]; 
					break;
				
				// 12
				case op_push_ic: 
					top = code + 1;
					break;
			}
		}
	}
};

#endif
